package server;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

import server.datamodel.Datamodel;

public class Connection extends Thread{
	private static final int STANDARD_PORT = 30456;
	
	private static Connection singleton;
	
	private HashMap<ConnectionHandler, DataOutputStream> clients;
	
	private Datamodel datamodel;
	
	private ServerSocket serverSocket;
	private int port;
	private boolean isRunning;
	
	private Connection(int port) {
		datamodel = new Datamodel();
		
		this.port = port;
		
		if(port <= 1024) {
			this.port = STANDARD_PORT;
		}
		
		clients = new HashMap<ConnectionHandler, DataOutputStream>();
		System.out.println("-initialized new server on port <" + this.port + ">");
	}
	
	@Override
	public synchronized void start() {
		isRunning = true;
		
		super.start();
	}
	
	@Override
	public void run() {
		new ConsoleListener().start();
		
		try {
			serverSocket = new ServerSocket(port);
			
			while(isRunning) {
				Socket socket = serverSocket.accept();
				
				System.out.println("-a new client connected: " + socket);
				
				DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
				
				ConnectionHandler connectionHandler = new ConnectionHandler(this, socket, dataOutputStream);
				new Thread(connectionHandler, "ConnectionHandler").start();
				
				clients.put(connectionHandler, dataOutputStream);
			}
			
		} catch(BindException be) {
			be.printStackTrace();
			System.out.println("close server");
			System.exit(0);
		} catch (IOException e) {
			System.out.println("server is closed");
		}
		
	}
	
	public void printClients() {
		System.out.println("-connected clients: ");
		
		for(ConnectionHandler handler: clients.keySet()) {
			System.out.println(" -" + handler.getSocket());
		}
	}
	
	public void disconnect(ConnectionHandler handler) {
		System.out.println("-client disconnected: " + handler.getSocket());
		
		clients.remove(handler);
	}
	
	public void broadcast(String message) {
		for(DataOutputStream o: clients.values()) {
			try {
				o.writeUTF(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void close() {
		isRunning = false;
		
		if(serverSocket != null) {
			try {
				for(ConnectionHandler handler: clients.keySet()) {
					handler.disconnect();
				}
				
				serverSocket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public HashMap<ConnectionHandler, DataOutputStream> getClients() {
		return clients;
	}
	
	public static Connection create(int port) {
		singleton = new Connection(port);
		singleton.start();
		return singleton;
	}
	
	public static Connection get() {
		return singleton;
	}
	
	public Datamodel getDatamodel() {
		return datamodel;
	}
}